#include <iostream>
#include <cstdlib>

#include <memory>// 包含 unique_ptr 头文件

/*
    GC---垃圾回收机制
*/

// 定义了两个类 Car 和 Person，并演示了它们之间的相互引用

class Person;// 前置申明
class Car
{
public:
    Car()
    {
        std::cout << "Car" << std::endl;
    }

    ~Car()
    {
        std::cout << "~Car()" << std::endl;
    }

public:
    // 智能指针，管理 Person 对象的生命周期，初始值为 nullptr。
    std::shared_ptr<Person> m_person = nullptr;
};

class Person
{
public:
    Person()
    {
        std::cout << "Person" << std::endl;
    }

    Person(int age):m_age(age)
    {
        std::cout << "Person(int age)" << std::endl;
    }

    ~Person()
    {
        std::cout << "~Person()" << std::endl;
    }

public:
    // 成员函数尽量 单独在另一个 public 中
    void run()
    {
        std::cout << "run()" << std::endl;
    }

public:
    // 智能指针，管理 Car 对象的生命周期，初始值为 nullptr。
    std::shared_ptr<Car> m_car = nullptr;

private:
    int m_age;
};


#if 0
// 智能指针 --- 内存托管
template <typename T>
class SmartPtr
{
public:
    SmartPtr(T * ptr)
    {
        m_ptr = ptr;    
    }

    ~SmartPtr()
    {
        if (m_ptr != nullptr)
        {
            delete m_ptr;
            m_ptr = nullptr;// 防止悬空指针
        }
    }

public:
    // 重载 -> 运算符 
    // 使 SmartPtr 对象可以使用 -> 操作符访问 T 的成员
    T * operator->()
    {
        return m_ptr;// 返回 m_ptr，从而使箭头操作符能够正常工作
    }

private:
    T * m_ptr;

};
#endif

#if 0
int main(int argc, char *argv[])
{
#if 0
    /*
        传统指针 存在的问题
        1. 需要手动管理内存
        2. 容易发生内存泄漏
        3. 释放之后不置 nullptr 会产生 野指针

    */
    char *ptr = (char *)malloc(sizeof(int) * 10);
    for (int i = 0; i < 10; i++)
    {
        ptr[i] = i;
    }
    free(ptr);
    ptr = nullptr;

    Person *p = new Person(20);
    p->run();
    delete p;// 手动释放
#endif

#if 0
    // 模仿引入智能指针 ：内存托管
    std::cout << "111" << std::endl;
    {
        int num = 100;
        std::auto_ptr<Person> p1(new Person(20));
        p1->run();
    }
    std::cout << "222" << std::endl;

    //  auto_ptr 已经被 弃用，不能用于数组
    // 不推荐使用 auto_ptr 它已被 弃用(deprecated)
    // 取而代之的是 std::unique_ptr 和 std::shared_ptr，它们提供了更好的内存管理功能和更安全的所有权语义。
    // auto_ptr<int> ptr1(new int(10));
    // {
    //     std::auto_ptr<int> p2(new int[100]);// 不能用于 数组 会有内存泄漏
    // }
    /*
        std::auto_ptr 使用独占所有权语义，这意味着它只能有一个拥有者。然而，std::auto_ptr 的所有权转移语义并不明确。
        例如，当一个 std::auto_ptr 被拷贝或赋值时，所有权会从源对象转移到目标对象，而源对象将不再拥有资源。这种隐式的所有权转移容易导致错误和意外的行为，特别是在容器和算法中使用时。
        std::auto_ptr<int> p1(new int(5));
        std::auto_ptr<int> p2 = p1; // p1 loses ownership, p2 now owns the int

        std::auto_ptr 的复制语义会导致所有权转移，因此它无法安全地与标准库容器（如 std::vector, std::list）一起使用。这是因为容器要求元素在复制或移动时行为良好，而 std::auto_ptr 的所有权转移会破坏这一点

        std::auto_ptr 不提供任何形式的线程安全保证
    */
#endif

    std::cout << "333" << std::endl;
    {
        // 创建一个 SmartPtr 对象 p2，
        // 管理一个 Person 对象指针，传递给 Person 构造函数的参数是 30
        SmartPtr<Person> p2(new Person(30));
        p2->run();
    }
    std::cout << "444" << std::endl;


    return 0;
}
#endif